package com.awenhui.demo.config.shiro;

import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.credential.PasswordMatcher;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.crypto.hash.format.HexFormat;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.sql.DataSource;
import javax.validation.constraints.Max;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @author yuxf
 * @version 1.0
 * @date 2020/12/21 16:10
 */
@Configuration
public class ShiroConfig {

    @Bean
    public ShrioRealm shrioRealm() {
        ShrioRealm shrioRealm = new ShrioRealm();
        //设置密码加密规则
        shrioRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return shrioRealm;
    }

    /**
     * 凭证匹配器
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(""));
        return hashedCredentialsMatcher;
    }

    @Bean
    public PhoneRealm phoneRealm() {
        PhoneRealm phoneRealm = new PhoneRealm();
        //PasswordMatcher
        PasswordMatcher passwordMatcher = new PasswordMatcher();
        passwordMatcher.setPasswordService(passwordService());
        phoneRealm.setCredentialsMatcher(passwordMatcher);
        return phoneRealm;
    }

    @Bean
    public PasswordService passwordService() {
        DefaultHashService hashService = new DefaultHashService();
        hashService.setHashIterations(3);
        hashService.setHashAlgorithmName("MD5");
        hashService.setGeneratePublicSalt(true);
        //设置HashService
        DefaultPasswordService passwordService = new DefaultPasswordService();
        passwordService.setHashService(hashService);
        // passwordService.setHashFormat(new HexFormat());
        return passwordService;
    }


    @Bean
    public JdbcRealm myJdbcRealm(DataSource dataSource) {
        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(dataSource);
        jdbcRealm.setPermissionsLookupEnabled(true);
        return jdbcRealm;
    }

    /**
     * 配置安全管理器
     *
     * @param shrioRealm
     * @return
     */
    @Bean("securityManager")
    public org.apache.shiro.mgt.SecurityManager securityManager(ShrioRealm shrioRealm, PhoneRealm phoneRealm, JdbcRealm jdbcRealm,RedisSessionDao redisSessionDao) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //注入
        defaultWebSecurityManager.setCacheManager(memoryConstrainedCacheManager());
//      //注入自定义myRealm
//      defaultWebSecurityManager.setRealm(shrioRealm);
        //设置多个realm,用户名密码登录realm,手机号短信验证码登录realm
        List<Realm> realms = new ArrayList<>();
        realms.add(shrioRealm);
        realms.add(phoneRealm);
        //realms.add(jdbcRealm);
        defaultWebSecurityManager.setRealms(realms);
        //如果是跨域项目无法从cookie中获取sessionid则从header中获取（shiro-token）
        //   defaultWebSecurityManager.setSessionManager(new HeaderWebSessionManager());
        //如果需要共享session，将session存入redis中
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDao);
        defaultWebSecurityManager.setSessionManager(sessionManager);
        return defaultWebSecurityManager;
    }



    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager securityManager) {
        //shiro对象
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        bean.setLoginUrl("/shiro/login");
        bean.setSuccessUrl("/shrio/index");
        //MAP
        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<String, String>();
        /*
        认证顺序是从上往下执行。
         */
        linkedHashMap.put("/logout", "logout");//在这儿配置登出地址，不需要专门去写控制器。
        linkedHashMap.put("/shiro/phoneLogin", "anon");
        linkedHashMap.put("/demo/**", "anon");
        linkedHashMap.put("/static/**", "anon");
        linkedHashMap.put("/css/**", "anon");
        linkedHashMap.put("/webjars/**", "anon");
        linkedHashMap.put("/thymeleaf/**", "anon");
        linkedHashMap.put("/swagger**/**", "anon");
        //开启注册页面不需要权限
        linkedHashMap.put("/shiro/anon", "anon");
        //    linkedHashMap.put("/**", "user");//需要进行权限验证
        bean.setFilterChainDefinitionMap(linkedHashMap);
        return bean;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 配置注解生效
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 配置注解生效
     *
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        sourceAdvisor.setSecurityManager(securityManager);
        return sourceAdvisor;
    }


    @Bean
    public CacheManager memoryConstrainedCacheManager() {
        return new MemoryConstrainedCacheManager();
    }
}
